<template>
  <div ref="canvas"></div>
</template>

<script lang="ts" setup>
import * as THREE from 'three';
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
import { GUI }  from "three/examples/jsm/libs/lil-gui.module.min.js";
import Stats from "three/examples/jsm/libs/stats.module";
import { TrackballControls } from "three/examples/jsm/controls/TrackballControls";
import { ref, onMounted } from "vue";

// 画布
const canvas = ref<any>('');
// 场景
const scene = new THREE.Scene();
// 相机
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.set(-30, 40, 30);
camera.lookAt(scene.position);
// 平面
const planeGeometry = new THREE.PlaneGeometry(60, 20);
const planeMaterial = new THREE.MeshLambertMaterial({
  color: 0xAAAAAA,
  side: THREE.DoubleSide,
});
const plane = new THREE.Mesh(planeGeometry, planeMaterial);
plane.rotation.x = -0.5 * Math.PI;
plane.position.set(15, 0, 0);
plane.receiveShadow = true;
// 正方体
const boxGeometry = new THREE.BoxGeometry(4, 4, 4);
const boxMaterial = new THREE.MeshLambertMaterial({
  color: 0xff0000,
});
const box = new THREE.Mesh(boxGeometry, boxMaterial);
box.position.set(-4, 3, 0);
box.castShadow = true;
// 球体
const sphereGeometry = new THREE.SphereGeometry(4, 20, 20);
const sphereMaterial = new THREE.MeshLambertMaterial({
  color: 0x7777ff,
});
const sphere = new THREE.Mesh(sphereGeometry, sphereMaterial);
sphere.position.set(20, 4, 2);
sphere.castShadow = true;
// 添加进场景
scene.add(plane, box, sphere);
// 光源
const spotLight = new THREE.SpotLight(0xffffff);
spotLight.position.set(-40, 40, -15);
spotLight.castShadow = true;
spotLight.shadow.mapSize = new THREE.Vector2(window.innerWidth, window.innerHeight);
spotLight.shadow.camera.far = 130;
spotLight.shadow.camera.near = 40;
scene.add(spotLight);
// 渲染器
const renderer = new THREE.WebGLRenderer({
  antialias: true,
});
renderer.setClearColor(0x000000);
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
// 相机控件
const orbitControl = new OrbitControls(camera, renderer.domElement);
orbitControl.update();
//
// 性能统计
const stat = Stats();
stat.setMode(0);
// 控制
const control = {
  rotation: false, // 是否旋转
  bounce: false, // 是否弹跳
  rotationSpeed: 0.01, // 旋转速度
  bounceSpeed: 0.02, // 弹跳速度
};
// gui界面
const gui = new GUI();
// @ts-ignore
gui.add(control, 'rotation').name("盒子旋转");
// @ts-ignore
gui.add(control, 'bounce').name("小球弹跳");
// @ts-ignore
gui.add(control, 'rotationSpeed', 0, 1).step(0.01).name("旋转速度");
// @ts-ignore
gui.add(control, 'bounceSpeed', 0, 1).step(0.01).name("弹跳速度");
// 小球弹跳速度
let step = control.bounceSpeed;
// 渲染函数
const render = () => {
  stat.update();
  // 正方体旋转
  if (control.rotation) {
    box.rotation.x += control.rotationSpeed;
    box.rotation.y += control.rotationSpeed;
    box.rotation.z += control.rotationSpeed;
  }
  // 小球弹跳
  if (control.bounce) {
    step += control.bounceSpeed;
    sphere.position.x = 20 + 10 * Math.cos(step);
    sphere.position.y = 2 + 10 * Math.abs(Math.sin(step));
  }

  renderer.render(scene, camera);
  requestAnimationFrame(render);
};

onMounted(() => {
  canvas.value.appendChild(renderer.domElement);
  canvas.value.appendChild(stat.domElement);
  render();
});

window.onresize = () => {
  console.log(' window.onresize .. ');
  // 浏览器尺寸改变时:
  //  1. 对于摄像机，需要更新它的aspect属性，这个属性表示屏幕的长宽比
  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix();
  //  2. 对于渲染器，需要改变它的像素比率，尺寸
  renderer.setPixelRatio(window.devicePixelRatio);
  renderer.setSize(window.innerWidth, window.innerHeight);
}

</script>
